﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace SMTPTestSuite
{
    class SMTPSessionOutgoing
    {
        private string _server;
        private int _port=25;
        private int _timeout = 15;
        Logging.Logger _Logger = null;

        public SMTPSessionOutgoing(string Server, int Port)
        {
            _server = Server;
            _port = Port;
        }

        public SMTPSessionOutgoing(string Server, int Port, Logging.Logger Logger)
            : this(Server, Port)
        {
            _Logger = Logger;
        }

        private void Log(string LogItem)
        {
            if (_Logger == null) return;
            _Logger.Log(LogItem);
        }

        /// <summary>
        /// SendMessage
        /// </summary>
        public string SendMessage(string MAILFROM, string RCPTTO, string DATA)
        {
            Log("Connecting to " + _server + ":" + _port);
            TcpClient oClient = null;
            try
            {
                oClient = new TcpClient(_server, _port);
            }
            catch (Exception ex)
            {
                Log("Connection failed: " + ex.Message);
                return null;
            }

            NetworkStream oStream = oClient.GetStream();

            while (!oStream.DataAvailable)
            Thread.Sleep(100);
            Byte[] data = new Byte[1024];
            String sData = String.Empty;
            while (oStream.DataAvailable)
            {
                Int32 bytes = oStream.Read(data, 0, data.Length);
                sData += System.Text.Encoding.ASCII.GetString(data, 0, bytes);
            }
            Log("<-- " + sData);

            string sResponse = SendData(oStream, "HELO SMTPTestClient");
            if (sResponse.ToLower().StartsWith("250"))
            {
                // MAIL FROM
                sResponse = SendData(oStream, "MAIL FROM:" + MAILFROM);
                if (sResponse.StartsWith("250"))
                {
                    // RCPT TO
                    bool bRecipValid = false;
                    if (RCPTTO.Contains(";"))
                    {
                        // Multiple recipients
                        string[] sRecips=RCPTTO.Split(';');
                        foreach (string sRecip in sRecips)
                        {
                            sResponse = SendData(oStream, "RCPT TO:" + sRecip);
                            if (!bRecipValid)
                                bRecipValid = (sResponse.StartsWith("250"));
                        }
                    }
                    else
                    {
                        // Single recipient
                        sResponse = SendData(oStream, "RCPT TO:" + RCPTTO);
                        bRecipValid = (sResponse.StartsWith("250"));
                    }

                    if (bRecipValid)
                    {
                        // DATA
                        sResponse = SendData(oStream, "DATA");
                        if (sResponse.StartsWith("354"))
                            sResponse = SendData(oStream, DATA + "\r\n.");
                    }
                }
                SendData(oStream, "QUIT", false);
            }
            oClient.Close();
            return sResponse;
        }

        private string SendData(NetworkStream Stream, string Data, bool ReadResponse=true)
        {
            Byte[] data = System.Text.Encoding.ASCII.GetBytes(Data + "\r\n");
            Stream.Write(data, 0, data.Length);
            Log("--> " + Data);
            if (!ReadResponse)
                return null;

            DateTime EndTime = DateTime.Now.AddSeconds(_timeout);
            while ((!Stream.DataAvailable) && (DateTime.Now<EndTime))
            {
                Thread.Sleep(100);
            }

            if (!Stream.DataAvailable)
            {
                Log("Time out waiting for response");
                return null;
            }

            data = new Byte[1024];
            String responseData = String.Empty;
            while (Stream.DataAvailable)
            {
                Int32 bytes = Stream.Read(data, 0, data.Length);
                responseData += System.Text.Encoding.ASCII.GetString(data, 0, bytes);
            }
            Log("<-- " + responseData);
            return responseData;

        }
    }
}
